﻿// Benn Eichhorn 2010
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Algobox.Feeds.Finance.Chix.CHIXMD
{
    /// <summary>
    /// Client library for accessing the Chi-X Market Data system and decoding messages
    /// </summary>
    public class ChiXMDClient : IDisposable
    {
        /// <summary>
        /// Creates an instance of the Chi-X MD market data client
        /// </summary>
        /// <param name="hostName">Host name or IP</param>
        /// <param name="hostPort">Host port </param>
        /// <param name="heartbeat">Hartbeat interval in milliseconds</param>
        public ChiXMDClient(string hostName, int hostPort, int heartbeat)
        {
            HostName = hostName;
            HostPort = hostPort;
            HeartbeatInterval = heartbeat;

            m_Comms = new Comms.Socket(this);
        }

        /// <summary>
        /// Chi-X MD destination IP address of hostname
        /// </summary>
        public string HostName { get; private set; }

        /// <summary>
        /// Chi-X MD destination port
        /// </summary>
        public int HostPort { get; private set; }

        /// <summary>
        /// Length in time in millisonds between heartbeats
        /// </summary>
        public int HeartbeatInterval { get; private set; }

        /// <summary>
        /// When communications are connect to Chi-X this is set to True
        /// </summary>
        public bool IsConnected { get; private set; }

        /// <summary>
        /// When communications are up are library is successfully logged in
        /// </summary>
        public bool IsLoggedIn { get; private set; }

        /// <summary>
        /// Communcations handler to the Chi-X market data system
        /// </summary>
        private Comms.Socket m_Comms;

        /// <summary>
        /// Possible states of the system
        /// </summary>
        public enum States
        {
            Disconnected,
            Connected,
            FailedToConnect,
            FailedToSend,
            FailedToRead,
            Logout,
            ThreadingIssue
        }

        internal States CurrentState { get; set; }

        /// <summary>
        /// Comms state change event delegate
        /// </summary>
        /// <param name="state"></param>
        public delegate void StateEvent(States state);

        /// <summary>
        /// Comms state changes will be pushed via this event
        /// </summary>
        public event StateEvent OnStateEvent;
                

        /// <summary>
        /// Send a state change event
        /// </summary>
        /// <param name="state"></param>
        internal void ProcessState(States state)
        {
            CurrentState = state;

            switch (state)
            {
                case States.Connected:
                    IsConnected = true;
                    break;
                case States.FailedToConnect:
                case States.Disconnected:
                    IsLoggedIn = false;
                    IsConnected = false;
                    break;
            }

            if (OnStateEvent != null)
                OnStateEvent(state);
        }

        /// <summary>
        /// Sequenced message event delegate
        /// </summary>
        /// <param name="message"></param>
        public delegate void MessageEvent(Messages.IMessage message);

        /// <summary>
        /// Sequenced messaged will be push via this event
        /// </summary>
        public event MessageEvent OnMessageEvent;

        /// <summary>
        /// Publish a sequenced message
        /// </summary>
        /// <param name="message"></param>
        internal void ProcessMessage(Messages.IMessage message)
        {
            if (OnMessageEvent != null)
                OnMessageEvent(message);
        }


        /// <summary>
        /// Connect and log into the Chi-X Market Data system
        /// </summary>
        /// <param name="userName">Market data user name</param>
        /// <param name="password">Market data password</param>
        /// <param name="sequenceNumber">Sequence you wish feed to start from (next expected). 1 indicates the beginning of the day. 0 indicates the last message generated by the system bypassing recovery.</param>
        /// <param name="result">Output message describing result of the login attempt (Messages.LoginAccept, Messages.LoginReject or Messages.Error)</param>
        /// <returns></returns>
        public bool Login(string userName, string password, int sequenceNumber, ref Messages.IMessage result)
        {
            return Login(userName, password, sequenceNumber, String.Empty, ref result);
        }

        /// <summary>
        /// Connect and log into the Chi-X Market Data system
        /// </summary>
        /// <param name="userName">Market data user name</param>
        /// <param name="password">Market data password</param>
        /// <param name="sequenceNumber">Sequence you wish feed to start from (next expected). 1 indicates the beginning of the day. 0 indicates the last message generated by the system bypassing recovery.</param>
        /// <param name="session">Requested session ID. For initial login leaving this field blank is recommended. For subsequent logins inclusion of the session ID is recommended.</param>
        /// <param name="result">Output message describing result of the login attempt (Messages.LoginAccept, Messages.LoginReject or Messages.Error)</param>
        /// <returns></returns>
        public bool Login(string userName, string password, int sequenceNumber, string session, ref Messages.IMessage result)
        {
            if (!IsLoggedIn)
            {
                if (!IsConnected)
                {
                    m_Comms.Initialise(HostName, HostPort);
                }
                if (m_Comms.Login(userName, password, session, sequenceNumber, ref result))
                {
                    IsLoggedIn = true;

                    // Start socket processing threads
                    m_Comms.StartProcessing();
                }
            }
            else
            {                
                result = Messages.Error.GetInstance("Login failed as already logged in");
            }

            return IsLoggedIn;
        }


        /// <summary>
        /// Logout and disconnect form the Chi-X Market Data system
        /// </summary>
        public void Logout()
        {
            m_Comms.Logout();
        }
                

        /// <summary>
        /// Logout and disconnect form the Chi-X Market Data system
        /// </summary>
        public void Dispose()
        {
            Logout();
            m_Comms.Dispose();
            m_Comms = null;
        }
    }
}
